import * as Cesium from 'cesium'

var ArcType = Cesium.ArcType;
var Cartesian3 = Cesium.Cartesian3;
var Color = Cesium.Color;
var defaultValue = Cesium.defaultValue;
var defined = Cesium.defined;
var destroyObject = Cesium.destroyObject;
var GeometryInstance = Cesium.GeometryInstance;
var Matrix4 = Cesium.Matrix4;
var PolylineGeometry = Cesium.PolylineGeometry;
var Primitive = Cesium.Primitive;
var PolylineMaterialAppearance = Cesium.PolylineMaterialAppearance;
var Material = Cesium.Material;


export default class Axis {
    constructor(viewer, modelMatrix, length, width, colorX, colorY, colorZ) {
        this.viewer = viewer;
        this.modelMatrix = modelMatrix;
        this.length = length;
        this.width = width;
        this.colorX = colorX;
        this.colorY = colorY;
        this.colorZ = colorZ;
        this.axisX = null;
        this.axisY = null;
        this.axisZ = null;

    }
    getAppearance(color = new Color(1.0, 0.0, 0.0, 1.0)){
        return new PolylineMaterialAppearance({
            material: new Material(
            {
                fabric: {
                type: Material.PolylineColorArrowType,
                uniforms: {
                    color: color,
                },
                source: `#ifdef GL_OES_standard_derivatives
                #extension GL_OES_standard_derivatives : enable
                #endif
                
                uniform vec4 color;
                
                float getPointOnLine(vec2 p0, vec2 p1, float x)
                {
                    float slope = (p0.y - p1.y) / (p0.x - p1.x);
                    return slope * (x - p0.x) + p0.y;
                }
                
                czm_material czm_getMaterial(czm_materialInput materialInput)
                {
                    czm_material material = czm_getDefaultMaterial(materialInput);
                
                    vec2 st = materialInput.st;
                
                #ifdef GL_OES_standard_derivatives
                    float base = 1.0 - abs(fwidth(st.s)) * 10.0 * czm_pixelRatio;
                #else
                    float base = 0.975; // 2.5% of the line will be the arrow head
                #endif
                
                    vec2 center = vec2(1.0, 0.5);
                    float ptOnUpperLine = getPointOnLine(vec2(base, 1.0), center, st.s);
                    float ptOnLowerLine = getPointOnLine(vec2(base, 0.0), center, st.s);
                
                    float halfWidth = 0.15;
                    float s = step(0.5 - halfWidth, st.t);
                    s *= 1.0 - step(0.5 + halfWidth, st.t);
                    s *= 1.0 - step(base, st.s);
                
                    float t = step(base, materialInput.st.s);
                    t *= 1.0 - step(ptOnUpperLine, st.t);
                    t *= step(ptOnLowerLine, st.t);
                
                    // Find the distance from the closest separator (region between two colors)
                    float dist;
                    if (st.s < base)
                    {
                        float d1 = abs(st.t - (0.5 - halfWidth));
                        float d2 = abs(st.t - (0.5 + halfWidth));
                        dist = min(d1, d2);
                    }
                    else
                    {
                        float d1 = czm_infinity;
                        if (st.t < 0.5 - halfWidth && st.t > 0.5 + halfWidth)
                        {
                            d1 = abs(st.s - base);
                        }
                        float d2 = abs(st.t - ptOnUpperLine);
                        float d3 = abs(st.t - ptOnLowerLine);
                        dist = min(min(d1, d2), d3);
                    }
                
                    vec4 outsideColor = vec4(0.0);
                    vec4 currentColor = mix(outsideColor, color, clamp(s + t, 0.0, 1.0));
                    vec4 outColor = czm_antialias(outsideColor, color, currentColor, dist);
                
                    outColor = czm_gammaCorrect(outColor);
                    material.diffuse = outColor.rgb;
                    material.alpha = outColor.a;
                    return material;
                }
                `,
                },
                translucent: true,
            }
            )
        })
    }

    renderAxis(){
        if (
            this.modelMatrix[12] === 0.0 &&
            this.modelMatrix[13] === 0.0 &&
            this.modelMatrix[14] === 0.0
        ) {
            this.modelMatrix[14] = 0.01;
        }
        
        var x = new GeometryInstance({
            geometry: new PolylineGeometry({
                positions: [Cartesian3.ZERO, Cartesian3.UNIT_X],
                width: this.width,
                vertexFormat: PolylineMaterialAppearance.VERTEX_FORMAT,
                colors: [Color.RED, Color.RED],
                arcType: ArcType.NONE,
            }),
            modelMatrix: Matrix4.multiplyByUniformScale(
                this.modelMatrix,
                this.length,
                new Matrix4()
            ),
            id: this.id,
            pickPrimitive: this,
        });
        var y = new GeometryInstance({
            geometry: new PolylineGeometry({
                positions: [Cartesian3.ZERO, Cartesian3.UNIT_Y],
                width: this.width,
                vertexFormat: PolylineMaterialAppearance.VERTEX_FORMAT,
                colors: [Color.GREEN, Color.GREEN],
                arcType: ArcType.NONE,
            }),
            modelMatrix: Matrix4.multiplyByUniformScale(
                this.modelMatrix,
                this.length,
                new Matrix4()
            ),
            id: this.id,
            pickPrimitive: this,
        });
        var z = new GeometryInstance({
            geometry: new PolylineGeometry({
                positions: [Cartesian3.ZERO, Cartesian3.UNIT_Z],
                width: this.width,
                vertexFormat: PolylineMaterialAppearance.VERTEX_FORMAT,
                colors: [Color.BLUE, Color.BLUE],
                arcType: ArcType.NONE,
            }),
            modelMatrix: Matrix4.multiplyByUniformScale(
                this.modelMatrix,
                this.length,
                new Matrix4()
            ),
            id: this.id,
            pickPrimitive: this,
        });
        this.axisX = new Primitive({
            geometryInstances: [x],
            appearance:  this.getAppearance(this.colorX),
            asynchronous: false,
        });
        this.axisY = new Primitive({
            geometryInstances: [y],
            appearance:  this.getAppearance(this.colorY),
            asynchronous: false,
        });
        this.axisZ = new Primitive({
            geometryInstances: [z],
            appearance:  this.getAppearance(this.colorZ),
            asynchronous: false,
        });

        this.viewer.scene.primitives.add(this.axisX);
        this.viewer.scene.primitives.add(this.axisY);
        this.viewer.scene.primitives.add(this.axisZ);
        
    }
    
    changeAxis(modelMatrix, length, width, colorX, colorY, colorZ){
        //更新参数
        this.modelMatrix = modelMatrix;
        this.length = length;
        this.width = width;
        this.colorX = colorX;
        this.colorY = colorY;
        this.colorZ = colorZ;
        //删除
        this.removeAxis()
        //重绘
        this.renderAxis()
    }
    removeAxis(){
        this.viewer.scene.primitives.remove(this.axisX);
        this.viewer.scene.primitives.remove(this.axisY);
        this.viewer.scene.primitives.remove(this.axisZ);
    }
}